#pragma once
#ifndef LIT__STREAM__HH__
#define LIT__STREAM__HH__

#include <LitPrerequisites.h>
#include <LitFilePath.h>
#include <LitNamed.hpp>

#include <fstream>
#include <sstream>
#include <vector>
#include <string>

//disable warnings on extern before template instantiation (per MS KB article)
#pragma warning (disable : 4231)

#ifdef LIT_C
#	ifdef LIT_UNICODE
	LIT_API_C template class std::basic_filebuf<wchar_t, std::char_traits<wchar_t>>;
	LIT_API_C template class std::basic_ofstream<wchar_t, std::char_traits<wchar_t>>;
	LIT_API_C template class std::basic_ifstream<wchar_t, std::char_traits<wchar_t>>;
	LIT_API_C template class std::basic_fstream<wchar_t, std::char_traits<wchar_t>>;
#	else
	LIT_API_C template class std::basic_filebuf<char, std::char_traits<char>>;;
	LIT_API_C template class std::basic_ofstream<char, std::char_traits<char>>;
	LIT_API_C template class std::basic_ifstream<char, std::char_traits<char>>;
	LIT_API_C template class std::basic_fstream<char, std::char_traits<char>>
#	endif
#else
#	ifdef LIT_UNICODE
	template class LIT_API std::basic_filebuf<wchar_t, std::char_traits<wchar_t>>;
	template class LIT_API std::basic_ofstream<wchar_t, std::char_traits<wchar_t>>;
	template class LIT_API std::basic_ifstream<wchar_t, std::char_traits<wchar_t>>;
	template class LIT_API std::basic_fstream<wchar_t, std::char_traits<wchar_t>>;
#	else
	template class LIT_API std::basic_filebuf<char, std::char_traits<char>>;
	template class LIT_API std::basic_ofstream<char, std::char_traits<char>>;
	template class LIT_API std::basic_ifstream<char, std::char_traits<char>>;
	template class LIT_API std::basic_fstream<char, std::char_traits<char>>;
#	endif
#endif

#pragma warning( default: 4231 )

namespace Lit
{
	class LIT_API Stream : public Named<false>
	{
	public:
		enum Access
		{
			ReadAccess=1<<1,
			WriteAccess=1<<2,
			BinaryAccess=1<<3,
			TextAccess=1<<4,
			TextRead=ReadAccess|TextAccess,
			TextWrite=WriteAccess|TextAccess,
			BinaryRead=ReadAccess|BinaryAccess,
			BinaryWrite=WriteAccess|BinaryAccess
		};
	protected:
		Access mAccess;
	public:
		Stream( Access access = TextRead );
		Stream( const String &name, Access access = TextRead );
		Stream( const Stream &rk );
		virtual ~Stream();

		Access getAccess() const;
		std::ios::open_mode getStdAccess() const;
		virtual size_t size() const = 0;
		virtual bool open( const String &name, Access access = TextRead ) = 0;
		virtual void close() = 0;
		virtual Stream& read( size_t num_chars, String & out ) = 0;
		virtual Stream& write( const String& str ) = 0;
		virtual Stream& readUntil( char c, String& out = String() ) = 0;
		virtual bool eof() const = 0;
		virtual bool valid() const = 0;
		String readLine();
		String readAll();
	};

	class LIT_API MemoryStreamPrivates;

	class LIT_API MemoryStream : public Stream
	{
	public:
		MemoryStream( Access access = TextRead );
		MemoryStream( const String &content, Access access = TextRead );
		MemoryStream( const String &name, const String &content, Access access = TextRead );
		MemoryStream( const MemoryStream &rk );
		~MemoryStream();
		
		size_t size() const;
		void close();
		bool open( const String &name = "", Access access = TextRead );
		MemoryStream& read( size_t num_chars, String & out );
		MemoryStream& write( const String& str );
		MemoryStream& readUntil( char c, String & out = String() );
		bool eof() const;
		bool valid() const;

	private:
		MemoryStreamPrivates* mPrivates;
		
		void _alloc();
		void _alloc( const MemoryStreamPrivates & rk);
		void _alloc( const String & content );

		void _dealloc();
	};
	
	class LIT_API FileStream : public Stream
	{
	public:
		FileStream( );
		FileStream( const String &name, Access access = TextRead );
		FileStream( const FileStream &rk );
		~FileStream();
		
		std::fstream& handle();
		const std::fstream& handle() const;

		size_t size() const;
		void close();
		bool open( const String &name = "", Access access = TextRead );
		FileStream& read( size_t num_chars, String & out );
		FileStream& write( const String& str );
		FileStream& readUntil( char c, String & out = String() );
		bool eof() const;
		bool valid() const;

	private:
		std::fstream mStream;
		size_t		mSize;
	};

	typedef RefPtr<Stream> StreamPtr;
	typedef RefPtr<MemoryStream> MemoryStreamPtr;
	typedef RefPtr<FileStream> FileStreamPtr;
};

#endif